package ms.jasim.console.gui;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;

import javax.swing.ActionMap;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import ms.jasim.console.JasimClientService;
import ms.spm.IAppContext;
import ms.spm.implement.SimpleMethodProvider;
import ms.spm.services.ActionCreator;
import chrriis.common.UIUtils;
import chrriis.dj.nativeswing.swtimpl.NativeInterface;

import com.vlsolutions.swing.docking.Dockable;
import com.vlsolutions.swing.docking.DockableResolver;
import com.vlsolutions.swing.docking.DockingDesktop;
import com.vlsolutions.swing.docking.DockingPreferences;

public class JasimConsole extends JFrame {

	private static final long serialVersionUID = 1L;
	private static final String PERSPECTIVE_FILE = "conf/consoleui.perspective.xml";
	/**
	 * Launch the application
	 * @param args
	 */
	public static void main(String args[]) {
		UIUtils.setPreferredLookAndFeel();
		NativeInterface.open();   
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					JasimConsole frame = new JasimConsole();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		NativeInterface.runEventPump();
	}

	enum Actions {
		SysConnect, SysDisconnect, SysExit, ShowAgentStatus, ShowActiveSolution, ShowControlPanel
	}
	
	private ActionMap actMap;
	protected IAppContext context;

	private ActionCreator svcActCreator;
	private JasimClientService svcJasim;
	private AgentTimelineDockPane agTimeline;
	private DockingDesktop desk;

	public JasimConsole() throws Exception {
		super();
		setSize(100, 700);
		setExtendedState(MAXIMIZED_BOTH);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//
		setupAppContext();
		initializesActions();
		createContent();

		this.addWindowListener( new WindowAdapter() {
			@Override
			public void windowClosed(WindowEvent e) {
				 try {
					    BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(PERSPECTIVE_FILE));
					    desk.writeXML(out);
					    out.close(); // stream isn't closed in case you'd like to save something else after
					  } catch (IOException ioe){
					  }
				super.windowClosed(e);
				System.exit(0);
			}
		});
	}

	private void createContent() {
		setJMenuBar(createJMenuBar());
		DockingPreferences.initHeavyWeightUsage();
		
		// ToolBarContainer container =
		// ToolBarContainer.createDefaultContainer(true, false, false, false);

		// VLToolBar bar = new VLToolBar();
		// bar.setName("Main");
		// container.registerToolBar(bar);
		//		
		// container.getToolBarPanelAt(BorderLayout.NORTH).add(bar, new
		// ToolBarConstraints(0, 0));
		
		desk = new DockingDesktop("main");
		desk.getContext().setDockableResolver(new DockableResolver() {
			@Override
			public Dockable resolveDockable(String keyName) {
				return createDockable(keyName);
			}
		});
		
		setContentPane(desk);
		
		agTimeline = new AgentTimelineDockPane(context);
		desk.registerDockable(agTimeline);
		desk.addDockable(agTimeline);
		
		loadDesktop();
	}
	
	private void loadDesktop() {
		try {
		    BufferedInputStream in = new BufferedInputStream(new FileInputStream(PERSPECTIVE_FILE));
		     
		    desk.readXML(in);
		    in.close(); // stream isn't closed
		} catch (Exception ioe) {
		} 
	}

	private void setupAppContext() throws Exception {
		context = ms.spm.implement.SimpleAppContext.createRootContext();

		context.addService(new SimpleMethodProvider(this, context));
		context.addService(svcJasim = new JasimClientService(context));

		svcActCreator = context.getService(ActionCreator.class);
		svcJasim.startPeriodicUpdate();
	}

	private void initializesActions() {
		actMap = new ActionMap();
		for (Actions act : Actions.values())
			actMap.put(act, svcActCreator.loadAction(act.toString()));

		actMap.get(Actions.SysDisconnect).setEnabled(false);
	}

	private JMenuBar createJMenuBar() {
		final JMenuBar menuBar = new JMenuBar();

		final JMenu systemMenu = new JMenu();
		systemMenu.setText("System");
		systemMenu.setMnemonic('S');
		menuBar.add(systemMenu);

		systemMenu.add(new JMenuItem(actMap.get(Actions.SysConnect)));
		systemMenu.add(new JMenuItem(actMap.get(Actions.SysDisconnect)));
		systemMenu.addSeparator();
		systemMenu.add(new JMenuItem(actMap.get(Actions.SysExit)));

		final JMenu windowsMenu = new JMenu();
		windowsMenu.setMnemonic('W');
		windowsMenu.setText("Windows");
		menuBar.add(windowsMenu);

		windowsMenu.add(new JMenuItem(actMap.get(Actions.ShowAgentStatus)));
		windowsMenu.add(new JMenuItem(actMap.get(Actions.ShowActiveSolution)));
		windowsMenu.add(new JMenuItem(actMap.get(Actions.ShowControlPanel)));
		return menuBar;
	}

	void connect(ActionEvent e) throws Exception {
		Actions act = Actions.valueOf(e.getActionCommand());
		if (act == Actions.SysConnect) {
			try {
				svcJasim.connect("localhost", 6668);
			} catch (Exception e1) {
				JOptionPane.showMessageDialog(null, "Unable to connect JasimServer\nReason: " + e1.getLocalizedMessage(), "Connect",
						JOptionPane.ERROR_MESSAGE);
			}
		} else {
			svcJasim.shutdown();
		}
		actMap.get(Actions.SysConnect).setEnabled(!svcJasim.Connected());
		actMap.get(Actions.SysDisconnect).setEnabled(svcJasim.Connected());
	}

	void stdAction(ActionEvent e) {
		Actions act = Actions.valueOf(e.getActionCommand());
		switch (act) {
		case SysExit:
			dispose();
			break;
		}
	}

	void showAgentWindows(ActionEvent e) throws Exception {
		Actions act = Actions.valueOf(e.getActionCommand());
		String className = null;
		switch (act) {
		case ShowAgentStatus:
			className = AgentStatusDockPane.class.getName();
			break;
		case ShowActiveSolution:
			className = ActiveSolutionDockPane.class.getName();
			break;			
		case ShowControlPanel:
			className = ControlDockPane.class.getName();
			break;
		}
		if (className != null) {
			Dockable d = desk.getContext().getDockableByKey(className);
			if (d != null)
				desk.addDockable(d);
			else if ((d = createDockable(className)) != null) {
				DefaultDockPane p = (DefaultDockPane) d;
				desk.split(agTimeline, d, p.getDefaultSplit());
			}
		}
	}

	@SuppressWarnings("unchecked")
	private Dockable createDockable(String keyName) {
		try {
			Class<? extends DefaultDockPane> dpClass = (Class<? extends DefaultDockPane>) Class.forName(keyName);
			Constructor ctor = dpClass.getConstructor(IAppContext.class);
			return (Dockable) ctor.newInstance(context);
		} catch (Exception e) {
			return null;
		}
	}

	
}
